package org.nuonuo.sdk.jackson;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @Version 1.0
 * @Author az
 * @Date 2023-11-30 09:45:47
 * @ClassName JsonUtils
 * @Description
 */
public class JsonMapper extends ObjectMapper {
    private static JsonMapper OBJECT_MAPPER;

    public static <T> T parse(String json) {
        return parse(json, Map.class);
    }

    public static <T> T parse(String json, Class<?> type) {
        return parse(json, type, null);
    }

    public static <T> T parse(String json, Class<?> type, Class<?> rawType) {
        if(isEmpty(json)) return null;
        try {
            ObjectMapper mapper = getObjectMapper();
            if (rawType != null && rawType != null) {
                return mapper.readValue(json, mapper.getTypeFactory().constructParametricType(type, rawType));
            }
            return rawType == null ? (T) mapper.readValue(json, type) : mapper.readValue(json, mapper.getTypeFactory().constructParametricType(List.class, rawType));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> T parseList(String json, Class<?> type, Class<?> rawType){
        if(isEmpty(json)) return null;
        try {
            JsonMapper mapper = getObjectMapper();
            return mapper.readValue(json,mapper.getTypeFactory().constructParametricType(type, mapper.createCollectionType(List.class, rawType)));
        } catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 构造泛型的Collection Type如:
     * ArrayList<MyBean>, 则调用constructCollectionType(ArrayList.class,MyBean.class)
     * HashMap<String,MyBean>, 则调用(HashMap.class,String.class, MyBean.class)
     */
    public JavaType createCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
        return this.getTypeFactory().constructParametricType(collectionClass, elementClasses);
    }

    public static <T> T parse(Object data, Class<?> type) {
        return parse(data, type, null);
    }

    public static <T> T parse(Object data, Class<?> type, Class<?> rawType) {
        return parse(data instanceof String ? (String) data : toJson(data), type, rawType);
    }

    public static String toJson(Object obj) {
        try {
            return obj == null ? null : obj instanceof String ? (String) obj: getObjectMapper().writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static JsonMapper getObjectMapper() {
        return null == OBJECT_MAPPER ? OBJECT_MAPPER = (JsonMapper) new JsonMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).setSerializationInclusion(JsonInclude.Include.NON_DEFAULT) : OBJECT_MAPPER;
    }

    public static boolean isEmpty(Object obj) {
        boolean result = false;
        if (obj == null || "null".equals(obj)) {
            result = true;
        }else{
            if (obj instanceof CharSequence) {
                result = ((CharSequence)obj).length() == 0;
            }else if (obj instanceof List) {
                result =((List<?>) obj).size()==0;
            }else if (obj instanceof Map) {
                result = ((Map<?, ?>) obj).isEmpty();
            }else if (obj instanceof Set) {
                result = ((Set<?>) obj).isEmpty();
            }else if (obj instanceof Object[]) {
                result = ((Object[]) obj).length==0;
            }
        }
        return result;
    }
    public static boolean isNotEmpty(Object obj) {
        return !isEmpty(obj);
    }
}
